home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Sample Code / Development Tools & Languages / AppsToGo / DTS.Lib / AEConnect.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-22  |  29.3 KB  |  935 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:        DTS.Lib
  5. ** File:        AEConnect.c
  6. ** Written by:  Eric Soldan
  7. **
  8. ** Copyright © 1990-1991 Apple Computer, Inc.
  9. ** All rights reserved.
  10. **
  11. ** This is the custom AppleEvents code used for establishing a connection
  12. ** to another window.  DTS.Lib targets a specific window in an application,
  13. ** not just an application.  It also sends and returns more information
  14. ** about the connection, such as user name, zone, and machine.  This
  15. ** information is two-way, so each user can know who they are connected to.
  16. */
  17.  
  18. /* You may incorporate this sample code into your applications without
  19. ** restriction, though the sample code has been provided "AS IS" and the
  20. ** responsibility for its operation is 100% yours.  However, what you are
  21. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  22. ** after having made changes. If you're going to re-distribute the source,
  23. ** we require that you make it clear in the source that the code was
  24. ** descended from Apple Sample Code, but that you've made changes. */
  25.  
  26.  
  27.  
  28. /*****************************************************************************/
  29.  
  30.  
  31.  
  32. #include "DTS.Lib2.h"
  33. #include "DTS.Lib.protos.h"
  34.  
  35. #ifndef __LOWMEM__
  36. #include <LowMem.h>
  37. #endif
  38.  
  39. #ifndef __RESOURCES__
  40. #include <Resources.h>
  41. #endif
  42.  
  43. #ifndef __TOOLUTILS__
  44. #include <ToolUtils.h>
  45. #endif
  46.  
  47.  
  48.  
  49. /*****************************************************************************/
  50.  
  51.  
  52.  
  53. extern OSType        gDocCreator;
  54. extern short        gMinVersion, gMaxVersion;
  55. extern Boolean        gHasAppleEvents;
  56. extern Cursor        *gCursorPtr;
  57.  
  58. static pascal OSErr        DoAEAnswer(AppleEvent *message, AppleEvent *reply, long refcon);
  59. static pascal OSErr        ReceiveConnect(AppleEvent *message, AppleEvent *reply, long refcon);
  60. static pascal OSErr        ReceiveConnectReply(AppleEvent *message, AppleEvent *reply);
  61.  
  62.  
  63.  
  64. /*****************************************************************************/
  65.  
  66.  
  67.  
  68. static AEHandler keywordsToInstall[] = {
  69.     { kCoreEventClass,        kAEAnswer,            (AEEventHandlerProcPtr)DoAEAnswer,        nil },
  70.     { kCustomEventClass,    keyAppConnect,        (AEEventHandlerProcPtr)ReceiveConnect,    nil },
  71. };        /* These are the custom AppleEvents. */
  72.  
  73. #define kNumKeywords (sizeof(keywordsToInstall) / sizeof(AEHandler))
  74.  
  75.  
  76.  
  77. /*****************************************************************************/
  78. /*****************************************************************************/
  79.  
  80. #ifdef applec
  81. #pragma segment ATGAppleEvents
  82. #endif
  83.  
  84. /*****************************************************************************/
  85. /*****************************************************************************/
  86.  
  87.  
  88.  
  89. /* Install the AppleEvents we use to establish a connection to a specific
  90. ** window.  This is done in addition to installing the required AppleEvents.
  91. ** InitAppleEvents, which installs the required AppleEvents, must be called
  92. ** first, since it sets up some global values. */
  93.  
  94. void    InitConnectAppleEvents(void)
  95. {
  96.     OSErr    err;
  97.     short    i;
  98.  
  99.     if (gHasAppleEvents) {
  100.         for (i = 0; i < kNumKeywords; ++i) {
  101.  
  102.             if (!keywordsToInstall[i].theUPP)
  103.                 keywordsToInstall[i].theUPP = NewAEEventHandlerProc(keywordsToInstall[i].theHandler);
  104.  
  105.             err = AEInstallEventHandler(
  106.                 keywordsToInstall[i].theEventClass,    /* What class to install.  */
  107.                 keywordsToInstall[i].theEventID,    /* Keywords to install.    */
  108.                 keywordsToInstall[i].theUPP,        /* The AppleEvent handler. */
  109.                 0L,                                    /* Unused refcon.           */
  110.                 false                                /* Only for our app.       */
  111.             );
  112.  
  113.             if (err) {
  114.                 HCenteredAlert(rErrorAlert, nil, gAlertFilterUPP);
  115.                 return;
  116.             }
  117.         }
  118.     }
  119. }
  120.  
  121.  
  122.  
  123. /*****************************************************************************/
  124.  
  125.  
  126.  
  127. /* This function handles the connect reply.  DTS.framework sends the connect request
  128. ** via kAEQueueReply.  This means that it doesn't necessarily come back immediately.
  129. ** (It actually comes back right away if it is connected to itself.)  The reply
  130. ** normally comes in via a high-level event.  Until this reply comes in, the
  131. ** connection isn't established.  When this reply does come in, the remaining
  132. ** information necessary to establish the connection to a particular window in
  133. ** the target application is recorded. */
  134.  
  135. static pascal OSErr    DoAEAnswer(AppleEvent *message, AppleEvent *reply, long refcon)
  136. {
  137. #ifndef __MWERKS__
  138. #pragma unused (refcon)
  139. #endif
  140.  
  141.     gCursorPtr = nil;        /* Force re-calc of cursor region and cursor to use. */
  142.     return(ReceiveConnectReply(message, reply));
  143. }
  144.  
  145.  
  146.  
  147. /*****************************************************************************/
  148.  
  149.  
  150.  
  151. /* This is the function that is called to establish a connection to another
  152. ** DTS.framework-based application.  The "other" DTS.framework-based application is probably
  153. ** the same application on another machine.  This code does a bit more than simply connecting
  154. ** to another application.  It targets a specific window within that application.  It doesn't
  155. ** just target zone/machine/application, which is the granularity that AppleEvents gives you.
  156. ** It also passes back and forth some information that is kind of a pain to get, but
  157. ** is nice to have.  One such piece of information is the user name.  This needs to be
  158. ** sent.  It can't be determined from the message from an AppleEvent.  The sender sends
  159. ** the user name, and the receiver returns the remote user name.  The user name is
  160. ** placed in the document record for the window to be used if you wish. */
  161.  
  162. OSErr    SendConnect(FileRecHndl frHndl, char *theLocNBPType)
  163. {
  164.     AEAddressDesc    remoteLoc;
  165.     OSErr            err;
  166.     long            windTag[2], size;
  167.     char            hstate;
  168.     Ptr                ptr1, ptr2;
  169.     AppleEvent        theAevt, reply;
  170.     Str255            macText, appText;
  171.     Str32            remoteName;
  172.     Handle            remoteNameHndl;
  173.     OSType            sftype;
  174.     FSSpec            myFSS;
  175.     Str255            thisPath;
  176.     Str32            thisApp;
  177.     static PPCFilterUPP    aePortFilterUPP = nil;
  178.  
  179.     err = noErr;
  180.  
  181.     theAevt.dataHandle = reply.dataHandle = nil;
  182.         /* Make sure disposing of the descriptors is okay in all cases.
  183.         ** theAevt and reply aren't necessarily instantiated correctly, so
  184.         ** we need to make sure that the dispose is safe, even if they aren't
  185.         ** valid.  theAevt isn't valid if MakeTarget returns an error.  If
  186.         ** MakeTarget returns an error, then AECreateAppleEvent isn't called
  187.         ** for theAevt.  Similarly, if AESend isn't called, reply isn't valid. */
  188.  
  189.     GetIndString(macText, rPPCText, sTitleText);
  190.     GetIndString(appText, rPPCText, sAppText);
  191.  
  192.     remoteLoc = (*frHndl)->connect.remoteLoc;
  193.     if (!remoteLoc.dataHandle) {
  194.         if (!aePortFilterUPP)
  195.             aePortFilterUPP = NewPPCFilterProc(AEPortFilter);
  196.         err = MakeTarget(&remoteLoc, false, kAEWaitReply, macText, appText,
  197.                         aePortFilterUPP, theLocNBPType);
  198.             /* Generate the target for the remote user. */
  199.     }
  200.  
  201.     (*frHndl)->connect.remoteLoc    = remoteLoc;
  202.     (*frHndl)->connect.windowTag[0] = windTag[0] = (TickCount() & 0xFFFFFFFE);
  203.     (*frHndl)->connect.windowTag[1] = windTag[0];
  204.         /* The windTag fields are used to determine which window is the target
  205.         ** for an incomming AppleEvent.  windTag[0] for the application doing
  206.         ** the connecting will be even, and windTag[1] (the target's ID) will
  207.         ** be odd.  This prevents any accidental occurance where the windTag
  208.         ** fields are the same.  The target application will store these values
  209.         ** reversed.  Any incomming AppleEvent, from either application, will
  210.         ** invert these fields and then scan the window list looking for a window
  211.         ** that has the correct values in these fields.  If there is no such
  212.         ** window, then the window was closed at some point.  Initially, the sender
  213.         ** sets these values to be the same.  Until the sender receives a return
  214.         ** reply for the connect message, the windows aren't officially connected.
  215.         ** When the reply comes in, then the windTag[1] field is set to the reply's
  216.         ** return value. */
  217.  
  218.     if (!err) {        /* Create the AppleEvent... */
  219.         err = AECreateAppleEvent(        /* Create empty AppleEvent.       */
  220.             kCustomEventClass,            /*   Event class.               */
  221.             typeAppConnect,                /*   Event ID.                   */
  222.             &remoteLoc,                    /*   Address of receiving app. */
  223.             kAutoGenerateReturnID,        /*   This value causes the       */
  224.                                         /*   AppleEvent manager to       */
  225.                                         /*   assign a return ID that   */
  226.                                         /*   is unique to the session. */
  227.             kAnyTransactionID,            /*   Ignore transaction ID.       */
  228.             &theAevt                    /*   Location of event.           */
  229.         );
  230.     }
  231.  
  232.     if (!err) {
  233.         sftype = (*frHndl)->fileState.sfType;
  234.         err = AEPutParamPtr(    /* Add document type to AppleEvent. */
  235.             &theAevt,            /*   AppleEvent to add to. */
  236.             keySFType,            /*   AEKeyword.               */
  237.             typeLongInteger,    /*   Actual type.           */
  238.             (Ptr)&sftype,        /*   Pointer to the data.  */
  239.             sizeof(OSType)        /*   Size of the data.       */
  240.         );
  241.     }
  242.  
  243.     if (!err) {
  244.         myFSS = (*frHndl)->fileState.fss;
  245.         err = AEPutParamPtr(    /* Add document name (which is in the FSSpec) to AppleEvent. */
  246.             &theAevt,            /*   AppleEvent to add to. */
  247.             keyFSS,                /*   AEKeyword.               */
  248.             typeFSS,            /*   Desired type.           */
  249.             (Ptr)&myFSS,        /*   Pointer to the data.  */
  250.             sizeof(FSSpec)        /*   Size of the data.       */
  251.         );
  252.     }
  253.  
  254.     if (!err) {
  255.         hstate = HGetState((Handle)frHndl);
  256.         HLock((Handle)frHndl);
  257.         ptr1   = (Ptr)&((*frHndl)->connect);
  258.         ptr2   = (Ptr)&((*frHndl)->connect.endSendInfo);
  259.         size   = (long)ptr2 - (long)ptr1;
  260.         err = AEPutParamPtr(    /* Add file connect info to the AppleEvent. */
  261.             &theAevt,            /*   AppleEvent to add to.             */
  262.             keyAppConnect,        /*   AEKeyword.                         */
  263.             typeAppConnect,        /*   Desired type.                     */
  264.             ptr1,                /*   Pointer to the data to be sent. */
  265.             size                /*   Size of the data to be sent.     */
  266.         );
  267.         HSetState((Handle)frHndl, hstate);
  268.     }
  269.  
  270.     if (!err) {
  271.         remoteName[0] = 0;
  272.         remoteNameHndl = GetAppResource('STR ', -16096, nil);
  273.         if (remoteNameHndl)
  274.             pcpy(remoteName, (StringPtr)(*remoteNameHndl));
  275.         err = AEPutParamPtr(    /* Add user name to AppleEvent. */
  276.             &theAevt,            /*   AppleEvent to add to. */
  277.             keyPascal,            /*   AEKeyword.               */
  278.             typePascal,            /*   Desired type.           */
  279.             (Ptr)remoteName,    /*   Pointer to the data.  */
  280.             remoteName[0] + 1    /*   Size of the data.       */
  281.         );
  282.     }
  283.  
  284.     if (!(*frHndl)->connect.remotePath[0]) (*frHndl)->connect.remoteApp[0]  = 0;
  285.     if (!(*frHndl)->connect.remoteApp[0])  (*frHndl)->connect.remotePath[0] = 0;
  286.  
  287.     if (!err) {
  288.         pcpy(thisPath, (*frHndl)->connect.remotePath);    /* We're the remote to the other guy. */
  289.         err = AEPutParamPtr(        /* Add user name to AppleEvent. */
  290.             &theAevt,                /*   AppleEvent to add to. */
  291.             typePascal2,            /*   AEKeyword.               */
  292.             typePascal2,            /*   Desired type.           */
  293.             (Ptr)thisPath,            /*   Pointer to the data.  */
  294.             thisPath[0] + 1            /*   Size of the data.       */
  295.         );
  296.     }
  297.     (*frHndl)->connect.remotePath[0] = 0;
  298.  
  299.     if (!err) {
  300.         pcpy(thisApp, (*frHndl)->connect.remoteApp);    /* We're the remote to the other guy. */
  301.         err = AEPutParamPtr(    /* Add user name to AppleEvent. */
  302.             &theAevt,            /*   AppleEvent to add to. */
  303.             typePascal3,        /*   AEKeyword.               */
  304.             typePascal3,        /*   Desired type.           */
  305.             (Ptr)thisApp,        /*   Pointer to the data.  */
  306.             thisApp[0] + 1        /*   Size of the data.       */
  307.         );
  308.     }
  309.     (*frHndl)->connect.remoteApp[0] = 0;
  310.  
  311.     if (!err) {        /* If we have an AppleEvent ready to send... */
  312.         err = AESend(            /* Send AppleEvent.              */
  313.             &theAevt,            /*   Our Apple Event to send. */
  314.             &reply,                /*   We may have a reply.      */
  315.             kAEQueueReply,        /*   Type of reply.              */
  316.             kAENormalPriority,    /*   App. send priority.      */
  317.             0,                    /*   We aren't waiting.          */
  318.             nil,                /*   We aren't waiting.          */
  319.             nil                    /*   EventFilterProcPtr.      */
  320.         );
  321.     }
  322.     if (remoteLoc.descriptorType == typeProcessSerialNumber)
  323.         err = ReceiveConnectReply(&reply, &reply);
  324.             /* If we want a queue reply, and if we are sending to ourselves,
  325.             ** then we already have the reply.  Since we are sending to
  326.             ** ourselves, everything happens right away, even for queue reply, so
  327.             ** we must handle the connect reply here.  If we are sending to another
  328.             ** machine, then the reply will come in as a high-level event and we
  329.             ** will process it through the event loop. */
  330.  
  331.     AEDisposeDesc(&theAevt);
  332.     AEDisposeDesc(&reply);
  333.         /* Dispose of the descriptors, created or not.
  334.         ** If not created, no harm done by calling. */
  335.  
  336.     if (err) {
  337.         AEDisposeDesc(&remoteLoc);
  338.         (*frHndl)->connect.remoteLoc.dataHandle = nil;
  339.             /* If we didn't connect, get rid of the target descriptor.  If we
  340.             ** succeeded at connecting, then we keep the descriptor until the
  341.             ** connection is broken by the application. */
  342.  
  343.         (*frHndl)->connect.windowTag[0] = 0;
  344.         (*frHndl)->connect.windowTag[1] = 0;
  345.             /* Mark this window so that it will never be found if we somehow
  346.             ** do get an answer from the receiver, even after failure. */
  347.     }
  348.  
  349.     return(err);
  350. }
  351.  
  352.  
  353.  
  354. /*****************************************************************************/
  355.  
  356.  
  357.  
  358. /* This function receives a connect message from SendConnect.  The connection
  359. ** tasks that the receiver has to do are done here, such as opening a window for
  360. ** this end of the connection, etc.  It also returns whether or not it succeeded,
  361. ** and the user name.  Basically, it establishes the connection, while keeping
  362. ** some data as to whom it is connected to. */
  363.  
  364. static pascal OSErr    ReceiveConnect(AppleEvent *message, AppleEvent *reply, long refcon)
  365. {
  366. #ifndef __MWERKS__
  367. #pragma unused (refcon)
  368. #endif
  369.  
  370.     OSErr            err;
  371.     FileRecHndl        frHndl;
  372.     char            hstate;
  373.     Ptr                ptr1, ptr2;
  374.     long            size, windTag[2];
  375.     AEAddressDesc    senderTarget;
  376.     DescType        ignoredType;
  377.     Size            ignoredSize;
  378.     OSType            sftype;
  379.     FSSpec            myFSS;
  380.     Str32            remoteZone, remoteMachine, remoteName, remoteApp;
  381.     Str255            theOtherPath, thisPath;
  382.     Str32            theOtherApp,  thisApp;
  383.     Handle            remoteNameHndl;
  384.     short            vers;
  385.  
  386.     err = AEGetParamPtr(    /* Get OSType to determine document type. */
  387.         message,            /*   The AppleEvent.            */
  388.         keySFType,            /*   AEKeyword                   */
  389.         typeLongInteger,    /*   Desired type.               */
  390.         &ignoredType,        /*   Type code.                   */
  391.         (Ptr)&sftype,        /*   Pointer to area for data. */ 
  392.         sizeof(OSType),        /*   Size of the data.           */
  393.         &ignoredSize        /*   Returned size of data.       */
  394.     );
  395.  
  396.     if (!err)
  397.         err = NewDocument(&frHndl, sftype, false);
  398.  
  399.     if (err) return(err);
  400.  
  401.     if (!err) {
  402.         hstate = HGetState((Handle)frHndl);
  403.         HLock((Handle)frHndl);
  404.         ptr1   = (Ptr)&((*frHndl)->connect);
  405.         ptr2   = (Ptr)&((*frHndl)->connect.endSendInfo);
  406.         size   = (long)ptr2 - (long)ptr1;
  407.         err = AEGetParamPtr(    /* Get connect info from the AppleEvent. */
  408.             message,            /*   The AppleEvent.            */
  409.             keyAppConnect,        /*   AEKeyword                   */
  410.             typeAppConnect,        /*   Desired type.               */
  411.             &ignoredType,        /*   Type code.                   */
  412.             ptr1,                /*   Pointer to area for data. */ 
  413.             size,                /*   Size of data area.           */
  414.             &ignoredSize        /*   Returned size of data.       */
  415.         );
  416.         HSetState((Handle)frHndl, hstate);
  417.     }
  418.  
  419.     if (!err) {
  420.         err = AEGetAttributeDesc(    /* Get address of sender.     */
  421.             message,                /*   Get address of sender from message. */
  422.             keyAddressAttr,            /*   We want an address.                 */
  423.             typeWildCard,            /*   We want the address of the sender.     */
  424.             &senderTarget            /*   Address of sender.                     */
  425.         );
  426.         if (!err) {
  427.             (*frHndl)->connect.remoteLoc = senderTarget;
  428.             err = AEGetParamPtr(    /* Get FSSpec (for document name) from AppleEvent. */
  429.                 message,            /*   The AppleEvent.            */
  430.                 keyFSS,                /*   AEKeyword                   */
  431.                 typeFSS,            /*   Desired type.               */
  432.                 &ignoredType,        /*   Type code.                   */
  433.                 (Ptr)&myFSS,        /*   Pointer to area for data. */ 
  434.                 sizeof(FSSpec),        /*   Size of the data.           */
  435.                 &ignoredSize        /*   Returned size of data.       */
  436.             );
  437.             if (!err)
  438.                 pcpy((*frHndl)->fileState.fss.name, (StringPtr)myFSS.name);
  439.         }
  440.         if (!err) {
  441.             err = AEGetParamPtr(    /* Get user name from AppleEvent. */
  442.                 message,            /*   The AppleEvent.            */
  443.                 keyPascal,            /*   AEKeyword                   */
  444.                 typePascal,            /*   Desired type.               */
  445.                 &ignoredType,        /*   Type code.                   */
  446.                 (Ptr)remoteName,    /*   Pointer to area for data. */ 
  447.                 sizeof(Str255),        /*   Size of the data.           */
  448.                 &ignoredSize        /*   Returned size of data.       */
  449.             );
  450.             (*frHndl)->connect.remoteName[0] = 0;
  451.             if (!err) {
  452.                 pcpy((*frHndl)->connect.remoteName, remoteName);
  453.                 remoteZone[0] = remoteMachine[0] = 0;
  454.                 GetTargetInfo(senderTarget, remoteZone, remoteMachine, remoteApp);
  455.                 pcpy((*frHndl)->connect.remoteZone, remoteZone);
  456.                 pcpy((*frHndl)->connect.remoteMachine, remoteMachine);
  457.             }
  458.         }
  459.  
  460.         theOtherPath[0] = theOtherApp[0] = 0;
  461.         if (!err) {
  462.             err = AEGetParamPtr(    /* Get user name from AppleEvent. */
  463.                 message,            /*   The AppleEvent.            */
  464.                 typePascal2,        /*   AEKeyword                   */
  465.                 typePascal2,        /*   Desired type.               */
  466.                 &ignoredType,        /*   Type code.                   */
  467.                 (Ptr)theOtherPath,    /*   Pointer to area for data. */ 
  468.                 sizeof(Str255),        /*   Size of the data.           */
  469.                 &ignoredSize        /*   Returned size of data.       */
  470.             );
  471.         }
  472.         if (!err) {
  473.             err = AEGetParamPtr(    /* Get user name from AppleEvent. */
  474.                 message,            /*   The AppleEvent.            */
  475.                 typePascal3,        /*   AEKeyword                   */
  476.                 typePascal3,        /*   Desired type.               */
  477.                 &ignoredType,        /*   Type code.                   */
  478.                 (Ptr)theOtherApp,    /*   Pointer to area for data. */ 
  479.                 sizeof(Str255),        /*   Size of the data.           */
  480.                 &ignoredSize        /*   Returned size of data.       */
  481.             );
  482.         }
  483.     }
  484.  
  485.     if (!err) {        /* If we got the remote user address... */
  486.  
  487.         (*frHndl)->connect.windowTag[0] = windTag[0] = (TickCount() | 0x01);
  488.         (*frHndl)->connect.connected = true;
  489.  
  490.         vers = (*frHndl)->d.doc.fhInfo.version;
  491.         if ((vers < gMinVersion) || (vers > gMaxVersion))
  492.             err = errAEWrongDataType;
  493.                 /* Incompatible file format. */
  494.  
  495.         if (!err) {
  496.             windTag[1] = (*frHndl)->connect.windowTag[1];
  497.             err = AEPutParamPtr(    /* Return receiver window ID. */
  498.                 reply,                /*   The AppleEvent.            */
  499.                 keyWindowTag,        /*   AEKeyword                   */
  500.                 typeDoubleLong,        /*   Type code.                   */
  501.                 (Ptr)&windTag[0],    /*   Pointer to area for data. */ 
  502.                 2 * sizeof(long)    /*   Size of data area.           */
  503.             );
  504.         }
  505.  
  506.         if (!err) {
  507.             remoteName[0] = 0;
  508.             remoteNameHndl = GetAppResource('STR ', -16096, nil);
  509.             if (remoteNameHndl)
  510.                 pcpy(remoteName, (StringPtr)(*remoteNameHndl));
  511.             err = AEPutParamPtr(    /* Return receiver user name. */
  512.                 reply,                /*   The AppleEvent.            */
  513.                 keyPascal,            /*   AEKeyword                   */
  514.                 typePascal,            /*   Type code.                   */
  515.                 (Ptr)remoteName,    /*   Pointer to area for data. */ 
  516.                 remoteName[0] + 1    /*   Size of data area.           */
  517.             );
  518.         }
  519.  
  520.         if (!err) {
  521.             if (theOtherPath[0]) {
  522.                 pcpy((*frHndl)->connect.remotePath, theOtherPath);
  523.                 pcpy((*frHndl)->connect.remoteApp,  theOtherApp);
  524.                 GetFullPathAndAppName(thisPath, thisApp);
  525.                 err = AEPutParamPtr(    /* Return receiver user name. */
  526.                     reply,                /*   The AppleEvent.            */
  527.                     typePascal2,        /*   AEKeyword                   */
  528.                     typePascal2,        /*   Type code.                   */
  529.                     (Ptr)thisPath,        /*   Pointer to area for data. */ 
  530.                     thisPath[0] + 1        /*   Size of data area.           */
  531.                 );
  532.                 if (!err) {
  533.                     err = AEPutParamPtr(    /* Return receiver user name. */
  534.                         reply,                /*   The AppleEvent.            */
  535.                         typePascal3,        /*   AEKeyword                   */
  536.                         typePascal3,        /*   Type code.                   */
  537.                         (Ptr)thisApp,        /*   Pointer to area for data. */ 
  538.                         thisApp[0] + 1        /*   Size of data area.           */
  539.                     );
  540.                 }
  541.             }
  542.         }
  543.  
  544.         if (!err)
  545.             err = DoNewWindow(frHndl, nil, GetNextWindow(nil, 0), (WindowPtr)-1);
  546.                 /* If connecting worked, create a window for the document. */
  547.     }
  548.  
  549.     if (err)
  550.         DisposeDocument(frHndl);
  551.  
  552.     if (!err)
  553.         NotifyUser();
  554.  
  555.     return(err);
  556. }
  557.  
  558.  
  559.  
  560. /*****************************************************************************/
  561.  
  562.  
  563.  
  564. /* This function is called when you want to determine which window an AppleEvent
  565. ** is targeted for.  DTS.framework AppleEvents send two long values along with the AppleEvent
  566. ** to determine which window is the target window.  One of the longs is an ID for the
  567. ** sender, and the other is an ID for the receiver.  When a connection is established,
  568. ** these values are saved for both the sender and the receiver.  This allows the
  569. ** AppleEvent to be sent in either direction and still be targeted to the correct window.
  570. ** To find which window is the target, get these two longs out of the AppleEvent and then
  571. ** call GetAEWindow.  The first value is always the ID of the machine itself, and the
  572. ** second value is always the ID of the remote machine.  Due to this, you will need to
  573. ** reverse the order of these ID's for incomming DTS.framework AppleEvents. */
  574.  
  575. static pascal OSErr    ReceiveConnectReply(AppleEvent *message, AppleEvent *reply)
  576. {
  577. #ifndef __MWERKS__
  578. #pragma unused (reply)
  579. #endif
  580.  
  581.     OSErr            err, replyErr;
  582.     DescType        actualType;
  583.     long            windTag[2], actualSize;
  584.     WindowPtr        window;
  585.     FileRecHndl        frHndl;
  586.     Str32            remoteZone, remoteMachine, remoteApp, remoteName;
  587.     Str255            theOtherPath;
  588.     Str32            theOtherApp;
  589.  
  590.     err = AEGetParamPtr(        /* Check for a receiver error... */
  591.         message,                /*   The AppleEvent.            */
  592.         keyReplyErr,            /*   AEKeyword                   */
  593.         typeShortInteger,        /*   Desired type.               */
  594.         &actualType,            /*   Type code.                   */
  595.         (Ptr)&replyErr,            /*   Pointer to area for data. */ 
  596.         sizeof(short),            /*   Size of data area.           */
  597.         &actualSize                /*   Returned size of data.       */
  598.     );
  599.     if (err == errAEDescNotFound)
  600.         err = noErr;
  601.     else
  602.         if (!err)
  603.             err = replyErr;
  604.  
  605.     if (!err) {
  606.         err = AEGetParamPtr(    /* Get receiver window ID. */
  607.             message,            /*   The AppleEvent.            */
  608.             keyWindowTag,        /*   AEKeyword                   */
  609.             typeDoubleLong,        /*   Desired type.               */
  610.             &actualType,        /*   Type code.                   */
  611.             (Ptr)&windTag[0],    /*   Pointer to area for data. */ 
  612.             2 * sizeof(long),    /*   Size of data area.           */
  613.             &actualSize            /*   Returned size of data.       */
  614.         );
  615.     }
  616.  
  617.     if (!err) {        /* If we got the receiver window ID... */
  618.  
  619.         window = GetAEWindow(windTag[1], windTag[1]);
  620.             /* The ID's are still both ours, since this is where we
  621.             ** get the receiver's ID returned.  windTag[0] holds the
  622.             ** receiver's ID, and windTag[1] holds ours. */
  623.  
  624.         if (window) {
  625.             frHndl = (FileRecHndl)GetWRefCon(window);
  626.             if (!(*frHndl)->connect.connected) {
  627.                 err = AEGetParamPtr(
  628.                     message,            /* The AppleEvent.              */
  629.                     keyPascal,            /* AEKeyword                 */
  630.                     typePascal,            /* Desired type.             */
  631.                     &actualType,        /* Type code.                 */
  632.                     (Ptr)remoteName,    /* Pointer to area for data. */ 
  633.                     sizeof(Str255),        /* Size of data area.         */
  634.                     &actualSize            /* Returned size of data.     */
  635.                 );
  636.  
  637.                 if (!err) {
  638.                     err = AEGetParamPtr(
  639.                         message,            /* The AppleEvent.              */
  640.                         typePascal2,        /* AEKeyword                 */
  641.                         typePascal2,        /* Desired type.             */
  642.                         &actualType,        /* Type code.                 */
  643.                         (Ptr)theOtherPath,    /* Pointer to area for data. */ 
  644.                         sizeof(Str255),        /* Size of data area.         */
  645.                         &actualSize            /* Returned size of data.     */
  646.                     );
  647.                 }
  648.                 if (err == errAEDescNotFound) {
  649.                     theOtherPath[0] = 0;
  650.                     err = noErr;
  651.                 }
  652.                 if (!err) {
  653.                     err = AEGetParamPtr(
  654.                         message,            /* The AppleEvent.              */
  655.                         typePascal3,        /* AEKeyword                 */
  656.                         typePascal3,        /* Desired type.             */
  657.                         &actualType,        /* Type code.                 */
  658.                         (Ptr)theOtherApp,    /* Pointer to area for data. */ 
  659.                         sizeof(Str255),        /* Size of data area.         */
  660.                         &actualSize            /* Returned size of data.     */
  661.                     );
  662.                 }
  663.                 if (err == errAEDescNotFound) {
  664.                     theOtherApp[0] = 0;
  665.                     err = noErr;
  666.                 }
  667.  
  668.                 (*frHndl)->connect.remoteName[0] = 0;
  669.                 if (!err) {        /* Connection is for sure, so remember what we need. */
  670.                     (*frHndl)->connect.windowTag[1] = windTag[0];
  671.                     pcpy((*frHndl)->connect.remoteName, remoteName);
  672.                     GetTargetInfo((*frHndl)->connect.remoteLoc,
  673.                                   remoteZone, remoteMachine, remoteApp);
  674.                     pcpy((*frHndl)->connect.remoteZone,    remoteZone);
  675.                     pcpy((*frHndl)->connect.remoteMachine, remoteMachine);
  676.                     pcpy((*frHndl)->connect.remotePath,    theOtherPath);
  677.                     pcpy((*frHndl)->connect.remoteApp,     theOtherApp);
  678.                     (*frHndl)->connect.connected = true;
  679.                 }
  680.                 else
  681.                     (*frHndl)->connect.windowTag[0] = (*frHndl)->connect.windowTag[1] = 0;
  682.             }
  683.         }
  684.     }
  685.  
  686.     return(err);
  687. }
  688.  
  689.  
  690.  
  691. /*****************************************************************************/
  692.  
  693.  
  694.  
  695. /* Find the window with the specified window ID's. */
  696.  
  697. WindowPtr    GetAEWindow(long windTag_0, long windTag_1)
  698. {
  699.     WindowPeek    window;
  700.     FileRecHndl    frHndl;
  701.  
  702.     for (window = LMGetWindowList(); window; window = window->nextWindow) {
  703.         if (IsAppWindow((WindowPtr)window)) {
  704.             frHndl = (FileRecHndl)GetWRefCon((WindowPtr)window);
  705.             if (
  706.                 ((*frHndl)->connect.windowTag[0] == windTag_0) &&
  707.                 ((*frHndl)->connect.windowTag[1] == windTag_1)
  708.             ) return((WindowPtr)window);
  709.         }
  710.     }
  711.  
  712.     return(nil);
  713. }
  714.  
  715.  
  716.  
  717. /*****************************************************************************/
  718.  
  719.  
  720.  
  721. void    GetFullPathAndAppName(StringPtr path, StringPtr app)
  722. {
  723.     ProcessSerialNumber    psn;
  724.     ProcessInfoRec        pinfo;
  725.     FSSpec                fss;
  726.  
  727.     pinfo.processInfoLength = sizeof(ProcessInfoRec);
  728.     pinfo.processName       = app;
  729.     pinfo.processAppSpec    = &fss;
  730.  
  731.     psn.lowLongOfPSN  = kCurrentProcess;
  732.     psn.highLongOfPSN = kNoProcess;
  733.     GetProcessInformation(&psn, &pinfo);
  734.  
  735.     PathNameFromDirID(pinfo.processAppSpec->parID, pinfo.processAppSpec->vRefNum, path);
  736. }
  737.  
  738.  
  739.  
  740. /*****************************************************************************/
  741.  
  742.  
  743.  
  744. void    AllowAutoReconnect(FileRecHndl frHndl)
  745. {
  746.     Str255    path;
  747.     Str32    app;
  748.  
  749.     GetFullPathAndAppName(path, app);
  750.     pcpy((*frHndl)->connect.remotePath, path);
  751.     pcpy((*frHndl)->connect.remoteApp,  app);
  752. }
  753.  
  754.  
  755.  
  756. /*****************************************************************************/
  757.  
  758.  
  759.  
  760. /* This function doesn't allow the PPCBrowser to display any applications other
  761. ** than the designated application(s). */
  762.  
  763. pascal Boolean    AEPortFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  764. {
  765. #ifndef __MWERKS__
  766. #pragma unused (locationName)
  767. #endif
  768.  
  769.     OSType    type;
  770.  
  771.     if (thePortInfo->name.portKindSelector == ppcByString) {
  772.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  773.             /* The BlockMove is so that we don't get an address error
  774.             ** on a 68000-based machine due to referencing a long at
  775.             ** an odd-address. */
  776.         if (type == gDocCreator) return(true);
  777.     }
  778.  
  779.     return(false);
  780. }
  781.  
  782.  
  783.  
  784. /*****************************************************************************/
  785.  
  786.  
  787.  
  788. OSErr    GetRemoteProcessTarget(FileRecHndl frHndl, AEDesc *retDesc, GRPTProcPtr proc)
  789. {
  790.     OSErr            err;
  791.     char            hstate;
  792.     PortInfoRec        info;        /* Just one, please. */
  793.     LocationNameRec    loc;
  794.     short            indx, reqCount, actCount;
  795.     TargetID        theID;
  796.  
  797.     retDesc->dataHandle = nil;        /* So caller can dispose always. */
  798.  
  799.     hstate = LockHandleHigh((Handle)frHndl);
  800.     loc.locationKindSelector = ppcNBPLocation;        /* Using an NBP construct. */
  801.     pcpy(loc.u.nbpEntity.objStr,  (*frHndl)->connect.remoteMachine);
  802.     pcpy(loc.u.nbpEntity.zoneStr, (*frHndl)->connect.remoteZone);
  803.     pcpy(loc.u.nbpEntity.typeStr, "\pPPCToolBox");
  804.     HSetState((Handle)frHndl, hstate);
  805.  
  806.     indx     = 0;
  807.     reqCount = 1;
  808.     actCount = 0;
  809.     err = DoIPCListPorts(&indx, &reqCount, &actCount, &loc, &info, proc);
  810.     if (err) return(err);
  811.  
  812.     if (actCount) {
  813.         theID.name = info.name;
  814.         theID.location = loc;
  815.         err = AECreateDesc(typeTargetID, (Ptr)&theID, sizeof(theID), retDesc);
  816.     }
  817.  
  818.     return(err);
  819. }
  820.  
  821.  
  822.  
  823. /*****************************************************************************/
  824.  
  825.  
  826.  
  827. /* Don't allow DoIPCListPorts to find anything but the finder. */
  828.  
  829. static pascal Boolean    FinderFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo);
  830. static pascal Boolean    FinderFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  831. {
  832. #ifndef __MWERKS__
  833. #pragma unused (locationName)
  834. #endif
  835.  
  836.     OSType    type;
  837.  
  838.     if (thePortInfo->name.portKindSelector == ppcByString) {
  839.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  840.             /* The BlockMove is so that we don't get an address error
  841.             ** on a 68000-based machine due to referencing a long at
  842.             ** an odd-address. */
  843.         if (type == 'MACS') return(true);
  844.     }
  845.  
  846.     return(false);
  847. }
  848.  
  849. /***/
  850.  
  851. OSErr    LaunchRemoteApp(FileRecHndl frHndl)
  852. {
  853.     OSErr            err;
  854.     AEDesc            remoteDesc, aeDirDesc, listElem, fileList;
  855.     AppleEvent        aevt, aeReply;
  856.     char            hstate;
  857.     Str255            path;
  858.     Str255            app;
  859.     AliasHandle        dirAlias, fileAlias;
  860.     ConnectRec        ac;
  861.  
  862.     err = noErr;
  863.     ac  = (*frHndl)->connect;
  864.  
  865.     if (ac.remotePath[0]) {
  866.  
  867.         DoSetCursor(*GetCursor(watchCursor));
  868.  
  869.         if (!GetRemoteProcessTarget(frHndl, &remoteDesc, FinderFilter)) {
  870.  
  871.             err = AECreateAppleEvent('FNDR', 'sope', &remoteDesc,
  872.                                       kAutoGenerateReturnID, kAnyTransactionID, &aevt);
  873.             AEDisposeDesc(&remoteDesc);
  874.  
  875.             if (!err) {
  876.  
  877.                 hstate = LockHandleHigh((Handle)frHndl);
  878.                 pcpy(path, (*frHndl)->connect.remotePath);
  879.                 pcpy(app, path);
  880.                 pcat(app,  (*frHndl)->connect.remoteApp);
  881.                 HSetState((Handle)frHndl, hstate);
  882.                 NewAliasMinimalFromFullPath(path[0], (path + 1), "\p", "\p", &dirAlias);
  883.                 NewAliasMinimalFromFullPath(app[0],  (app + 1),  "\p", "\p", &fileAlias);
  884.  
  885.                 err = AECreateList(nil, 0, false, &fileList);
  886.  
  887.                 if (!err) {
  888.                     hstate = LockHandleHigh((Handle)dirAlias);
  889.                     err = AECreateDesc(typeAlias, (Ptr)*dirAlias,
  890.                                        GetHandleSize((Handle)dirAlias), &aeDirDesc);
  891.                     HSetState((Handle)dirAlias, hstate);
  892.                 }
  893.                 DisposeHandle((Handle)dirAlias);
  894.  
  895.                 if (!err) {
  896.                     err = AEPutParamDesc(&aevt, keyDirectObject, &aeDirDesc);
  897.                     AEDisposeDesc(&aeDirDesc);
  898.                 }
  899.  
  900.                 if (!err) {
  901.                     hstate = LockHandleHigh((Handle)fileAlias);
  902.                     err = AECreateDesc(typeAlias, (Ptr)*fileAlias,
  903.                                        GetHandleSize((Handle)fileAlias), &listElem);
  904.                     HSetState((Handle)dirAlias, hstate);
  905.                 }
  906.                 DisposeHandle((Handle)fileAlias);
  907.  
  908.                 if (!err) {
  909.                     err = AEPutDesc(&fileList, 0, &listElem);
  910.                     AEDisposeDesc(&listElem);
  911.                 }
  912.  
  913.                 if (!err) {
  914.                     err = AEPutParamDesc(&aevt, 'fsel', &fileList);
  915.                     AEDisposeDesc(&fileList);
  916.                 }
  917.  
  918.                 if (!err) {
  919.                     err = AESend(&aevt, &aeReply,
  920.                                 (kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer),
  921.                                 kAENormalPriority, kAEDefaultTimeout, nil, nil);
  922.                     AEDisposeDesc(&aeReply);
  923.                 }
  924.  
  925.                 AEDisposeDesc(&aevt);
  926.             }
  927.         }
  928.     }
  929.  
  930.     return(err);
  931. }
  932.  
  933.  
  934.  
  935.